// @Author miaoqing
// @Date 2024/03/01 17:03:00
// @Desc
package logic

import (
	"core/command"
	"core/common"
	"core/component/function"
	"core/component/logger"
	"runtime/debug"
	"sync"
)

var (
	onlineClientMgr *OnlineClientMgr
	onceMgr         sync.Once
)

type Handler func(center *command.OnlineMsgToCenter)

type OnlineClientMgr struct {
	endpoints         *sync.Map
	topicChanelClient *sync.Map //map[topic]map[serverID]int
	handler           map[command.CenterCommand]Handler
	recvOnlineCh      chan interface{}
	removeClient      chan string
	registerTopic     chan *common.ReqRegisterTopicToCenter
	stop              chan int
}

func onlineClientMgrGetMe() *OnlineClientMgr {
	onceMgr.Do(func() {
		onlineClientMgr = &OnlineClientMgr{
			endpoints:         &sync.Map{},
			topicChanelClient: &sync.Map{},
			handler:           make(map[command.CenterCommand]Handler),
			recvOnlineCh:      make(chan interface{}, 128*1024),
			removeClient:      make(chan string, 1024),
			registerTopic:     make(chan *common.ReqRegisterTopicToCenter, 1024),
			stop:              make(chan int, 1),
		}
		onlineClientMgr.Register()
		go onlineClientMgr.loop()
	})
	return onlineClientMgr
}

func (mgr *OnlineClientMgr) registerTopicOnlineServer(topic, serverID string) {
	val, ok := mgr.topicChanelClient.Load(topic)
	if ok {
		m := val.(map[string]int)
		if _, exist := m[serverID]; exist {
			return
		}
		m[serverID] = 1
		mgr.topicChanelClient.Store(topic, m)
	} else {
		m := make(map[string]int)
		m[serverID] = 1
		mgr.topicChanelClient.Store(topic, m)
	}
	logger.Infof("Online Register Topic:%v OnlineServerID:%v", topic, serverID)
}

func (mgr *OnlineClientMgr) Register() {
	mgr.handler[command.CenterCommand_PublishToOnlineMsg_Center] = mgr.publishMsgToOtherClient
}

func (mgr *OnlineClientMgr) loop() {
	defer func() {
		if err := recover(); err != nil {
			function.WritePanic(string(debug.Stack()), err)
			return
		}
	}()
	for {
		select {
		case msg := <-mgr.recvOnlineCh:
			info, ok := msg.(*command.OnlineMsgToCenter)
			if !ok {
				return
			}
			mgr.onMessage(info)
		case msg := <-mgr.registerTopic:
			mgr.registerTopicOnlineServer(msg.Topic, msg.ServerID)
		case serverID := <-mgr.removeClient:
			mgr.removeOnlineClient(serverID)
		case <-mgr.stop:
			return
		}
	}
}

func (mgr *OnlineClientMgr) removeOnlineClient(serverID string) {
	mgr.endpoints.Delete(serverID)
}

func (mgr *OnlineClientMgr) onMessage(msg *command.OnlineMsgToCenter) {
	handler, ok := mgr.handler[msg.Cmd]
	if !ok {
		return
	}
	handler(msg)
}

func (mgr *OnlineClientMgr) sendMsgToOnline(serverID string, msg interface{}) bool {
	val, ok := mgr.endpoints.Load(serverID)
	if !ok {
		return false
	}
	data, _ := val.(*OnlineClient).Marshal(uint16(command.CenterCommand_CenterMsgToOnline_Center), msg)
	return val.(*OnlineClient).sendRowMsg(data)
}

func (mgr *OnlineClientMgr) addOnlineClient(sc *OnlineClient, srvID, srvAddr string, proIndx uint32) {
	val, ok := mgr.endpoints.Load(srvID)
	if ok {
		oldClient, _ := val.(*OnlineClient)
		if sc != oldClient {
			oldClient.Close()
		}
	}
	sc.srvID = srvID
	sc.srvAddr = srvAddr
	sc.proIndx = proIndx
	mgr.endpoints.Store(srvID, sc)
	logger.Infof("Online服务器连接到Center服务器 OnlineServer:%v Center:%v", srvID, ServerInstance().id)
}
